import 'dart:math';
import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame/particles.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hero_back/study/flutter_game_flame/day005/components/hero.dart';
import 'package:hero_back/study/flutter_game_flame/day007/ground.dart';
import 'package:hero_back/study/flutter_game_flame/day007/rock.dart';

import '../day004/component/adventurer.dart';
import 'background.dart';

class ParticleGame extends FlameGame
    with
        KeyboardEvents,
        HasCollisionDetection,
        HasTappables,
        HasKeyboardHandlerComponents {
  late Particle particle;
  late HeroComponent heroComponent;
  late Adventurer adventurer;

  @override
  Future<void>? onLoad() async {
    List<Sprite> sprites = [];
    for (int i = 0; i <= 8; i++) {
      sprites.add(await loadSprite('adventurer/adventurer-bow-0$i.png'));
    }
    SpriteAnimation animation =
        SpriteAnimation.spriteList(sprites, stepTime: 0.1, loop: false);
    heroComponent = HeroComponent(
        initPosition: size / 2,
        attr: HeroAttr(
            life: 100,
            speed: 50,
            attackSpeed: 10,
            attackRange: 10,
            attack: 10,
            crit: .5,
            critDamage: 10),
        spriteAnimation: animation,
        size: Vector2(40, 40));
    // add(heroComponent);
    // createParticle();
    // createPaintParticle();

    final Vector2 fixSize = Vector2(
      500,
      300,
    );
    camera.viewport = FixedResolutionViewport(fixSize);
    camera.setRelativeOffset(Anchor.center);
    camera.speed = 1;
    adventurer = Adventurer();
    camera.followComponent(adventurer);
    add(Background());
    add(adventurer);
    // for (var i = 0; i < 30; i++) {
    //   add(Rock(Vector2(Ground.genCoord(), Ground.genCoord())));
    // }
    return super.onLoad();
  }

  void createParticle() {
    Paint circlePaint = Paint()..color = Colors.white;
    particle = MovingParticle(
      from: Vector2.zero(),
      to: Vector2(200, 100),
      curve: Curves.easeIn,
      child: CircleParticle(paint: circlePaint, radius: 20),
      lifespan: 3,
    );
    final ParticleSystemComponent particleSystemComponent =
        ParticleSystemComponent(
      position: size / 2,
      particle: particle,
    );
    add(particleSystemComponent);
  }

  void createPaintParticle() {
    final List<Color> colors = [
      const Color(0xffff0000),
      const Color(0xff00ff00),
      const Color(0xff0000ff),
    ];
    final List<Vector2> positions = [
      Vector2(-10, 10),
      Vector2(10, 10),
      Vector2(0, -14)
    ];
    particle = Particle.generate(
      count: 3,
      lifespan: 3,
      generator: (i) => PaintParticle(
        child: MovingParticle(
          curve: Curves.easeIn,
          child: CircleParticle(
            paint: Paint()..color = colors[i],
            radius: 20,
          ),
          to: i == 0 ? positions.last : positions[i - 1],
          from: positions[i],
        ),
        paint: Paint()..blendMode = BlendMode.difference,
      ),
    );
    final ParticleSystemComponent particleSystemComponent =
        ParticleSystemComponent(
      position: size / 2,
      particle: particle,
    );
    add(particleSystemComponent);
  }

  void addMoveByEffect() {
    Effect effect = MoveByEffect(
        Vector2(10, -10), EffectController(duration: 1), onComplete: () {
      print("====onFinishCallBack");
    });
    heroComponent.add(effect);
  }

  void moveToCenter() {
    Effect effect = MoveToEffect(
      size / 2,
      EffectController(duration: .5),
    );
    heroComponent.add(effect);
  }

  void addRotateEffectBy() {
    Effect effect = RotateEffect.by(
      15 / 180 * pi,
      EffectController(duration: .5),
    );
    heroComponent.add(effect);
  }

  void addRotateEffectTo() {
    Effect effect = RotateEffect.to(
      0,
      EffectController(duration: .5),
    );
    heroComponent.add(effect);
  }

  void addScaleEffectBy() {
    Effect effect =
        ScaleEffect.by(Vector2(1.2, 1.2), EffectController(duration: .5));
    adventurer.add(effect);
  }

  void addScaleEffectTo() {
    Effect effect =
        ScaleEffect.to(Vector2(1, 1), EffectController(duration: .5));
    adventurer.add(effect);
  }

  void addRemoveEffect() {
    Effect effect = RemoveEffect(
      delay: 3,
    );
    heroComponent.add(effect);
  }

  void addSizeEffectBy() {
    Effect effect = SizeEffect.by(
      Vector2(5, 5 * (37 / 50)),
      EffectController(duration: 0.5),
    );
    adventurer.add(effect);
  }

  void addSizeEffectTo() {
    Effect effect = SizeEffect.to(
      Vector2(50, 37),
      EffectController(duration: .5),
    );
    adventurer.add(effect);
  }

  void addOpacityEffectBy() {
    Effect effect = OpacityEffect.by(
      -0.1,
      EffectController(duration: .5),
    );
    adventurer.add(effect);
  }

  void addOpacityEffectTo() {
    Effect effect = OpacityEffect.to(
      1,
      EffectController(duration: .5),
    );
    adventurer.add(effect);
  }

  void addColorEffect() {
    final effect = ColorEffect(
      Colors.blue,
      Offset(0, .4),
      EffectController(duration: 1),
    );
    adventurer.add(effect);
  }

  void addMoveAlongPathEffect() {
    Path path = Path()..quadraticBezierTo(50, -50, 100, 0);
    final Effect effect = MoveAlongPathEffect(
      path,
      EffectController(duration: 1.5),
    );
    adventurer.add(effect);
  }

  void linearEffectController() {
    EffectController ctrl = LinearEffectController(2);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void curvedEffectController() {
    EffectController ctrl = CurvedEffectController(2, Curves.easeIn);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void reverseLinearEffectController() {
    EffectController ctrl = ReverseLinearEffectController(2);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void reverseCurvedEffectController() {
    EffectController ctrl = ReverseCurvedEffectController(2, Curves.easeIn);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void sineEffectController() {
    EffectController ctrl = SineEffectController(period: 2);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void noiseEffectController() {
    EffectController ctrl = NoiseEffectController(frequency: 30, duration: 1);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void zigzagEffectController() {
    EffectController ctrl = ZigzagEffectController(period: 2);
    Effect effect = MoveByEffect(Vector2(0, -100), ctrl);
    adventurer.add(effect);
  }

  void pauseEffectController() {
    EffectController ctrl = PauseEffectController(2, progress: 1.0);
    Effect effect = MoveByEffect(Vector2(0, -10), ctrl);
    adventurer.add(effect);
  }

  void delayedEffectController() {
    EffectController child = CurvedEffectController(2, Curves.ease);
    EffectController controller = DelayedEffectController(child, delay: 2);
    Effect effect = MoveByEffect(Vector2(0, -100), controller);
    adventurer.add(effect);
  }

  void repeatedEffectController() {
    EffectController child = SineEffectController(period: .1);
    EffectController controller = RepeatedEffectController(child, 50);
    Effect effect = MoveByEffect(Vector2(-2, 0), controller);
    adventurer.add(effect);
  }

  void infiniteEffectController() {
    EffectController child = SineEffectController(period: 0.1);
    EffectController ctrl2 = InfiniteEffectController(child);
    Effect effect = MoveByEffect(
      Vector2(-2, 0),
      ctrl2,
    );
    adventurer.add(effect);
  }

  void removeEffect() {
    adventurer.removeAll(adventurer.children.whereType<Effect>());
  }

  void speedEffectController() {
    DurationEffectController child = LinearEffectController(2);
    EffectController controller = SpeedEffectController(child, speed: 10);
    Effect effect = MoveByEffect(Vector2(0, -100), controller);
    adventurer.add(effect);
  }

  void sequenceEffectController() {
    DurationEffectController child1 = LinearEffectController(2);
    EffectController child2 = ZigzagEffectController(period: 2);
    EffectController child3 = CurvedEffectController(2, Curves.ease);
    EffectController controller = SequenceEffectController([
      child1,
      child2,
      child3,
    ]);
    Effect effect = MoveByEffect(Vector2(0, -100), controller);
    adventurer.add(effect);
  }

  @override
  KeyEventResult onKeyEvent(
      RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
    final isKeyDown = event is RawKeyDownEvent;
    if (event.logicalKey == LogicalKeyboardKey.keyZ && isKeyDown) {
      camera.zoom += 0.1;
    }
    if (event.logicalKey == LogicalKeyboardKey.keyX && isKeyDown) {
      camera.zoom -= 0.1;
    }
    if (event.logicalKey == LogicalKeyboardKey.arrowUp && isKeyDown) {
      camera.moveTo(Vector2(0, size.y / 2 - 37 / 2));
    }
    if (event.logicalKey == LogicalKeyboardKey.digit1 && isKeyDown) {
      // addMoveByEffect();
      // linearEffectController();
      // curvedEffectController();
      // reverseLinearEffectController();
      // reverseCurvedEffectController();
      // sineEffectController();
      // noiseEffectController();
      // zigzagEffectController();
      // pauseEffectController();
      // delayedEffectController();
      // repeatedEffectController();
      // infiniteEffectController();
      // speedEffectController();
      sequenceEffectController();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit2 && isKeyDown) {
      removeEffect();
      // moveToCenter();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit3 && isKeyDown) {
      addRotateEffectBy();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit4 && isKeyDown) {
      addRotateEffectTo();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit5 && isKeyDown) {
      addScaleEffectBy();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit6 && isKeyDown) {
      addScaleEffectTo();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit7 && isKeyDown) {
      addRemoveEffect();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit8 && isKeyDown) {
      addSizeEffectBy();
    }
    if (event.logicalKey == LogicalKeyboardKey.digit9 && isKeyDown) {
      addSizeEffectTo();
    }
    if (event.logicalKey == LogicalKeyboardKey.keyQ && isKeyDown) {
      addOpacityEffectBy();
    }
    if (event.logicalKey == LogicalKeyboardKey.keyW && isKeyDown) {
      addOpacityEffectTo();
    }
    if (event.logicalKey == LogicalKeyboardKey.keyE && isKeyDown) {
      addColorEffect();
    }
    if (event.logicalKey == LogicalKeyboardKey.keyR && isKeyDown) {
      addMoveAlongPathEffect();
    }
    return super.onKeyEvent(event, keysPressed);
  }
}
